package heap

type Object struct {
	class *Klass      // 特定的指向 java.lang.Class的元数据 即指向 java.lang.Class.Klass
	data  interface{} //数据  //存储在内存中的数据
	extra interface{} // 指向真实类的元数据  xxx.xxx.Test2.Klass
}

// obj 是否是 class 的实例
func (obj *Object) IsInstanceOf(class *Klass) bool {
	return class.IsAssignableFrom(obj.class)
}

// obj 对象中 成员变量
func (obj *Object) Fields() Slots {
	return obj.data.(Slots)
}

// jclass  返回  java.lang.Class
// object  返回的 类指针
func (obj *Object) Class() *Klass {
	return obj.class
}

// jclass 返回 类指针
// object 返回 额外数据 待定???
func (obj Object) Extra() interface{} {
	return obj.extra
}

func (obj *Object) SetExtra(extra interface{}) {
	obj.extra = extra
}

func (obj *Object) SetRefVar(name string, descriptor string, ref *Object) {
	feild := obj.class.getField(name, descriptor, false)
	slots := obj.data.(Slots)
	slots.SetRef(feild.SlotId(), ref)
}

func (o *Object) GetRefVar(name string, descriptor string) *Object {
	field := o.class.getField(name, descriptor, false)
	slots := o.data.(Slots)
	return slots.GetRef(field.slotId)
}

func (o *Object) Refs() []*Object {
	return o.data.([]*Object)
}

func (o *Object) Shorts() []int16 {
	return o.data.([]int16)
}

func (o *Object) ArrayLength() int32 {
	switch o.data.(type) {
	case []int8:
		return int32(len(o.data.([]int8)))
	case []int16:
		return int32(len(o.data.([]int16)))
	case []int32:
		return int32(len(o.data.([]int32)))
	case []int64:
		return int32(len(o.data.([]int64)))
	case []uint16:
		return int32(len(o.data.([]uint16)))
	case []float32:
		return int32(len(o.data.([]float32)))
	case []float64:
		return int32(len(o.data.([]float64)))
	case []*Object:
		return int32(len(o.data.([]*Object)))
	default:
		panic("Not array!")
	}
}

func (self *Object) Bytes() []int8 {
	return self.data.([]int8)
}

func (obj *Object) Chars() []uint16 {
	return obj.data.([]uint16)
}

func (obj *Object) Doubles() []float64 {
	return obj.data.([]float64)
}

func (obj *Object) Floats() []float32 {
	return obj.data.([]float32)
}

func (o *Object) Ints() []int32 {
	return o.data.([]int32)
}

func (obj *Object) Longs() []int64 {
	return obj.data.([]int64)
}

func (obj *Object) Data() interface{} {
	return obj.data

}

func (obj *Object) GetIntVar(name, descriptor string) int32 {
	field := obj.class.getField(name, descriptor, false)
	slots := obj.data.(Slots)
	return slots.GetInt(field.slotId)
}

func (o *Object) SetIntVar(name, descriptor string, val int32) {
	field := o.class.getField(name, descriptor, false)
	slots := o.data.(Slots)
	slots.SetInt(field.slotId, val)
}

func (o *Object) Clone() *Object {
	return &Object{
		class: o.class,
		data:  o.cloneData(),
	}
}

func (o *Object) cloneData() interface{} {
	switch o.data.(type) {
	case []int8:
		elements := o.data.([]int8)
		elements2 := make([]int8, len(elements))
		copy(elements2, elements)
		return elements2
	case []int16:
		elements := o.data.([]int16)
		elements2 := make([]int16, len(elements))
		copy(elements2, elements)
		return elements2
	case []uint16:
		elements := o.data.([]uint16)
		elements2 := make([]uint16, len(elements))
		copy(elements2, elements)
		return elements2
	case []int32:
		elements := o.data.([]int32)
		elements2 := make([]int32, len(elements))
		copy(elements2, elements)
		return elements2
	case []int64:
		elements := o.data.([]int64)
		elements2 := make([]int64, len(elements))
		copy(elements2, elements)
		return elements2
	case []float32:
		elements := o.data.([]float32)
		elements2 := make([]float32, len(elements))
		copy(elements2, elements)
		return elements2
	case []float64:
		elements := o.data.([]float64)
		elements2 := make([]float64, len(elements))
		copy(elements2, elements)
		return elements2
	case []*Object:
		elements := o.data.([]*Object)
		elements2 := make([]*Object, len(elements))
		copy(elements2, elements)
		return elements2
	default: // []Slot
		slots := o.data.(Slots)
		slots2 := newSlots(uint(len(slots)))
		copy(slots2, slots)
		return slots2
	}
}

func ArrayCopy(src, dest *Object, srcPos, destPos, length int32) {
	switch d := src.data.(type) {
	case []int8:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]int8)[destPos : destPos+length]
		copy(_dest, _src)
	case []int16:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]int16)[destPos : destPos+length]
		copy(_dest, _src)
	case []int64:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]int64)[destPos : destPos+length]
		copy(_dest, _src)
	case []uint16:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]uint16)[destPos : destPos+length]
		copy(_dest, _src)
	case []float32:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]float32)[destPos : destPos+length]
		copy(_dest, _src)
	case []float64:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]float64)[destPos : destPos+length]
		copy(_dest, _src)
	case []int32:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]int32)[destPos : destPos+length]
		copy(_dest, _src)
	case []*Object:
		_src := d[srcPos : srcPos+length]
		_dest := dest.data.([]*Object)[destPos : destPos+length]
		copy(_dest, _src)
	default:
		panic("Not array!")
	}
}
